package com.github.jlmd.animatedcircleloadingview.component.finish;

import com.github.jlmd.animatedcircleloadingview.animator.AnimationState;
import com.github.jlmd.animatedcircleloadingview.animator.MyStateChange;
import com.github.jlmd.animatedcircleloadingview.animator.MyValueAnimator;
import com.github.jlmd.animatedcircleloadingview.component.ComponentViewAnimation;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;
import ohos.agp.render.BlendMode;
import ohos.agp.render.Canvas;
import ohos.agp.render.ColorFilter;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.Size;

import java.io.IOException;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author jlmd
 */
public abstract class FinishedView extends ComponentViewAnimation implements Component.DrawTask {

    private static final int MIN_IMAGE_SIZE = 1;
    protected final Color tintColor;
    private int maxImageSize;
    private int circleMaxRadius;
    private PixelMap originalFinishedBitmap;
    private float currentCircleRadius;
    private int imageSize;
    private Context context;

    public FinishedView(Context context, int parentWidth, Color mainColor, Color secondaryColor,
                        Color tintColor) {
        super(context, parentWidth, mainColor, secondaryColor);
        this.tintColor = tintColor;
        this.context = context;
        init();
        addDrawTask(this);
    }

    private void init() {
        maxImageSize = (140 * parentWidth) / 700;
        circleMaxRadius = (140 * parentWidth) / 700;
        currentCircleRadius = circleRadius;
        imageSize = MIN_IMAGE_SIZE;
        originalFinishedBitmap = getPixelMap(context, getDrawable()).get();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        drawCircle(canvas);
        drawCheckedMark(canvas);
    }

    private void drawCheckedMark(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColorFilter(new ColorFilter(getDrawableTintColor().getValue(), BlendMode.LIGHTEN));
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.size = new Size(imageSize, imageSize);
        PixelMap pixelMap = PixelMap.create(originalFinishedBitmap, options);
        PixelMapHolder pixelMapHolder = new PixelMapHolder(pixelMap);
        canvas.drawPixelMapHolder(pixelMapHolder,
                parentCenter - pixelMap.getImageInfo().size.width / 2,
                parentCenter - pixelMap.getImageInfo().size.height / 2,
                paint);
    }

    public void drawCircle(Canvas canvas) {
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
        paint.setColor(getCircleColor());
        paint.setAntiAlias(true);
        canvas.drawCircle(parentCenter, parentCenter, currentCircleRadius, paint);
    }

    public void startScaleAnimation() {
        startScaleCircleAnimation();
        startScaleImageAnimation();
    }

    private void startScaleCircleAnimation() {
        MyValueAnimator valueCircleAnimator = new MyValueAnimator();
        valueCircleAnimator.setFloat(circleRadius + strokeWidth / 2, circleMaxRadius);
        valueCircleAnimator.setDuration(1000);
        valueCircleAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                currentCircleRadius = value;
                invalidate();
            }
        });
        valueCircleAnimator.start();
    }

    private void startScaleImageAnimation() {
        MyValueAnimator valueImageAnimator = new MyValueAnimator();
        valueImageAnimator.setFloat(MIN_IMAGE_SIZE, maxImageSize);
        valueImageAnimator.setDuration(1000);
        valueImageAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                imageSize = (int) value;
                invalidate();
            }
        });
        valueImageAnimator.setStateChangedListener(new MyStateChange() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                setState(AnimationState.ANIMATION_END);
            }
        });
        valueImageAnimator.start();
    }

    protected abstract int getDrawable();

    protected abstract Color getDrawableTintColor();

    protected abstract Color getCircleColor();

    /**
     * get the pixel map
     *
     * @param context the context
     * @param id      the id
     * @return the pixel map
     */
    public static Optional<PixelMap> getPixelMap(Context context, int id) {
        String path = getPathById(context, id);
        if (path == null || path.length() <= 0) {
            return Optional.empty();
        }
        RawFileEntry assetManager = context.getResourceManager().getRawFileEntry(path);
        ImageSource.SourceOptions options = new ImageSource.SourceOptions();
        options.formatHint = "image/png";
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        try {
            Resource asset = assetManager.openRawFile();
            ImageSource source = ImageSource.create(asset, options);
            return Optional.ofNullable(source.createPixelmap(decodingOptions));
        } catch (IOException ex) {
            Logger.getLogger(FinishedView.class.getName()).log(Level.SEVERE, ex.getMessage());
        }
        return Optional.empty();
    }

    /**
     * get the path from id
     *
     * @param context the context
     * @param id      the id
     * @return the path from id
     */
    public static String getPathById(Context context, int id) {
        String path = "";
        if (context == null) {
            return path;
        }
        ResourceManager manager = context.getResourceManager();
        if (manager == null) {
            return path;
        }
        try {
            path = manager.getMediaPath(id);
        } catch (IOException | NotExistException | WrongTypeException ex) {
            Logger.getLogger(FinishedView.class.getName()).log(Level.SEVERE, ex.getMessage());
        }
        return path;
    }
}
